/*-------------------------------------------------------------------------
 *
 * rangetypes.h
 *	  PostgreSQL 范围类型的声明。
 *
 *
 * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 * src/include/utils/rangetypes.h
 *
 *-------------------------------------------------------------------------
 */
#ifndef RANGETYPES_H
#define RANGETYPES_H

#include "utils/typcache.h"


/*
 * 范围是 varlena 对象，因此必须满足 varlena 约定，
 * 对象的第一个 int32 包含对象的总字节大小。
 * 但是，请确保使用 VARSIZE() 和 SET_VARSIZE() 访问它！
 */
typedef struct
{
	int32		vl_len_;		/* varlena 头部（请勿直接触摸！） */
	Oid			rangetypid;		/* 范围类型自身的 OID */
	/* OID 后跟零到两个边界值，然后是一个标志字节 */
} RangeType;

#define RANGE_EMPTY_LITERAL "empty"

/* 优先使用此宏，而不是直接获取 rangetypid 字段 */
#define RangeTypeGetOid(r)	((r)->rangetypid)

/* 范围的标志字节包含这些位： */
#define RANGE_EMPTY			0x01	/* 范围为空 */
#define RANGE_LB_INC		0x02	/* 下边界是闭合的 */
#define RANGE_UB_INC		0x04	/* 上边界是闭合的 */
#define RANGE_LB_INF		0x08	/* 下边界是 -infinity */
#define RANGE_UB_INF		0x10	/* 上边界是 +infinity */
#define RANGE_LB_NULL		0x20	/* 下边界为 null（未使用） */
#define RANGE_UB_NULL		0x40	/* 上边界为 null（未使用） */
#define RANGE_CONTAIN_EMPTY 0x80	/* 标记一个 GiST 内部页面条目，其
									 * 子树包含一些空范围 */

#define RANGE_HAS_LBOUND(flags) (!((flags) & (RANGE_EMPTY | \
											  RANGE_LB_NULL | \
											  RANGE_LB_INF)))

#define RANGE_HAS_UBOUND(flags) (!((flags) & (RANGE_EMPTY | \
											  RANGE_UB_NULL | \
											  RANGE_UB_INF)))

#define RangeIsEmpty(r)  ((range_get_flags(r) & RANGE_EMPTY) != 0)
#define RangeIsOrContainsEmpty(r)  \
	((range_get_flags(r) & (RANGE_EMPTY | RANGE_CONTAIN_EMPTY)) != 0)


/* 范围的任一边界的内部表示（不是磁盘上的内容） */
typedef struct
{
	Datum		val;			/* 边界值（如果有） */
	bool		infinite;		/* 界限是 +/- 无穷大 */
	bool		inclusive;		/* 边界是闭合的（与开放的相对） */
	bool		lower;			/* 这是下边界（与上边界相对） */
} RangeBound;

/*
 * 范围类型对象的 fmgr 宏
 */
#define DatumGetRangeTypeP(X)		((RangeType *) PG_DETOAST_DATUM(X))
#define DatumGetRangeTypePCopy(X)	((RangeType *) PG_DETOAST_DATUM_COPY(X))
#define RangeTypePGetDatum(X)		PointerGetDatum(X)
#define PG_GETARG_RANGE_P(n)		DatumGetRangeTypeP(PG_GETARG_DATUM(n))
#define PG_GETARG_RANGE_P_COPY(n)	DatumGetRangeTypePCopy(PG_GETARG_DATUM(n))
#define PG_RETURN_RANGE_P(x)		return RangeTypePGetDatum(x)

/* 在 GiST 和 SP-GiST 范围操作类中使用的运算符策略编号 */
/* 数字的选择旨在将运算符名称与现有用法匹配 */
#define RANGESTRAT_BEFORE				RTLeftStrategyNumber
#define RANGESTRAT_OVERLEFT				RTOverLeftStrategyNumber
#define RANGESTRAT_OVERLAPS				RTOverlapStrategyNumber
#define RANGESTRAT_OVERRIGHT			RTOverRightStrategyNumber
#define RANGESTRAT_AFTER				RTRightStrategyNumber
#define RANGESTRAT_ADJACENT				RTSameStrategyNumber
#define RANGESTRAT_CONTAINS				RTContainsStrategyNumber
#define RANGESTRAT_CONTAINED_BY			RTContainedByStrategyNumber
#define RANGESTRAT_CONTAINS_ELEM		RTContainsElemStrategyNumber
#define RANGESTRAT_EQ					RTEqualStrategyNumber

/*
 * 在 rangetypes.c 中定义的函数的原型
 */

extern bool range_contains_elem_internal(TypeCacheEntry *typcache, const RangeType *r, Datum val);

/* 上述内容的内部版本 */
extern bool range_eq_internal(TypeCacheEntry *typcache, const RangeType *r1,
							  const RangeType *r2);
extern bool range_ne_internal(TypeCacheEntry *typcache, const RangeType *r1,
							  const RangeType *r2);
extern bool range_contains_internal(TypeCacheEntry *typcache, const RangeType *r1,
									const RangeType *r2);
extern bool range_contained_by_internal(TypeCacheEntry *typcache, const RangeType *r1,
										const RangeType *r2);
extern bool range_before_internal(TypeCacheEntry *typcache, const RangeType *r1,
								  const RangeType *r2);
extern bool range_after_internal(TypeCacheEntry *typcache, const RangeType *r1,
								 const RangeType *r2);
extern bool range_adjacent_internal(TypeCacheEntry *typcache, const RangeType *r1,
									const RangeType *r2);
extern bool range_overlaps_internal(TypeCacheEntry *typcache, const RangeType *r1,
									const RangeType *r2);
extern bool range_overleft_internal(TypeCacheEntry *typcache, const RangeType *r1,
									const RangeType *r2);
extern bool range_overright_internal(TypeCacheEntry *typcache, const RangeType *r1,
									 const RangeType *r2);
extern RangeType *range_union_internal(TypeCacheEntry *typcache, RangeType *r1,
									   RangeType *r2, bool strict);
extern RangeType *range_minus_internal(TypeCacheEntry *typcache, RangeType *r1,
									   RangeType *r2);
extern RangeType *range_intersect_internal(TypeCacheEntry *typcache, const RangeType *r1,
										   const RangeType *r2);

/* 各种支持函数 */
extern TypeCacheEntry *range_get_typcache(FunctionCallInfo fcinfo,
										  Oid rngtypid);
extern RangeType *range_serialize(TypeCacheEntry *typcache, RangeBound *lower,
								  RangeBound *upper, bool empty);
extern void range_deserialize(TypeCacheEntry *typcache, const RangeType *range,
							  RangeBound *lower, RangeBound *upper,
							  bool *empty);
extern char range_get_flags(const RangeType *range);
extern void range_set_contain_empty(RangeType *range);
extern RangeType *make_range(TypeCacheEntry *typcache, RangeBound *lower,
							 RangeBound *upper, bool empty);
extern int	range_cmp_bounds(TypeCacheEntry *typcache, const RangeBound *b1,
							 const RangeBound *b2);
extern int	range_cmp_bound_values(TypeCacheEntry *typcache, const RangeBound *b1,
								   const RangeBound *b2);
extern int	range_compare(const void *key1, const void *key2, void *arg);
extern bool bounds_adjacent(TypeCacheEntry *typcache, RangeBound bound1,
							RangeBound bound2);
extern RangeType *make_empty_range(TypeCacheEntry *typcache);
extern bool range_split_internal(TypeCacheEntry *typcache, const RangeType *r1,
								 const RangeType *r2, RangeType **output1,
								 RangeType **output2);

#endif							/* RANGETYPES_H */
